﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IdentityModel.Tokens.Jwt;
using Cl.Utils.Primitives.Enum;
using Cl.Utils.Helper;
using Cl.Utils.Helper.Encryption.SHA256;
using Cl.Entity.DataBaseEntity.User;
using Cl.Model.Results;
using Cl.Repository;
using Cl.Utils.Primitives.Class;
using Cl.Model.DataBaseEntityDtos.User.RegisterUsers;
using Cl.Utils.Helper.AutoMap;
using Cl.Utils.Primitives.Const.UserLogin;
using Cl.Utils;
using MediatR;
using Cl.Model.DataBaseEntityDtos.User.UserLogins;

namespace Cl.Service.Service.User.UserLogins
{
    public class UserLoginService : IUserLoginService
    {
        #region 依赖注入

        private ClRepository<Entity.DataBaseEntity.User.User> _userRepository;

        private ClRepository<UserLogin> _userLoginsRepository;


        private ClRepository<UserRole> UserRoleRepository;


        private ClRepository<Role> RoleRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="accountRepository"></param>
        /// <param name="accountLoginRepository"></param>
        /// <param name="groupMainRepository"></param>
        public UserLoginService(ClRepository<Entity.DataBaseEntity.User.User> userRepository, ClRepository<UserLogin> userLoginsRepository,
           ClRepository<UserRole> userRoleRepository, ClRepository<Role> roleRepository)
        {
            _userRepository = userRepository;
            _userLoginsRepository = userLoginsRepository;
            UserRoleRepository = userRoleRepository;
            RoleRepository = roleRepository;
        }

        #endregion


        #region 接口实现

        public ResultInfoModel RegisterUser(RegisterUserInputDto obj)
        {
            try
            {
                //校验电话唯一性
                var checkPhone = _userRepository.AsQueryable().Any(it => it.Phone == obj.Phone);
                if (checkPhone)
                    return GetResult.Error("已注册");

                _userRepository.BeginTran();

                //数据准备
                var operationData = AutoMapHelper.MapTo<RegisterUserInputDto, Entity.DataBaseEntity.User.User>(obj);
                operationData.Account = operationData.Phone;
                operationData.CreateTime = DateTime.Now;
                operationData.IsEnable = 1;
                var _user = _userRepository.AsInsertable(operationData).ExecuteReturnEntity();

                //注册（信息，来源：根据不同来源设置不同的账号权限）
                switch (obj.RegisterSourse)
                {
                    case ClientTypeConst.Customer:
                        //获取客户角色的ID
                        var roleInfo = RoleRepository.GetFirst(x => x.Name == GlobalService.DefaultData.CustomerRoleName);
                        if (roleInfo != null)
                        {
                            UserRoleRepository.AsInsertable(new UserRole()
                            {
                                UserId = _user.Id,
                                RoleId = roleInfo.Id,
                                CreateId = _user.Id,
                                CreateTime = DateTime.Now
                            }).ExecuteCommand();
                        }
                        break;
                }
                _userRepository.CommitTran();


                return GetResult.Success();
            }
            catch (Exception ex)
            {
                _userRepository.RollbackTran();
                return GetResult.Error(ex.Message);
            }
        }


        public ResultInfoModel Login(LoginRequest request)
        {

            //string identifier, string password
            var identifier = request.Identifier;
            var password = request.Password;


            #region 验证

            if (string.IsNullOrEmpty(identifier) || string.IsNullOrEmpty(password))
            {
                return GetResult.Error("请输入信息");
            }

            var userInfo = _userRepository.AsQueryable()
                .Includes(r => r.UserRoles, ri => ri.Role)
                .First(x => x.IsEnable == 1 && (x.Account.ToLower() == identifier.ToLower() || x.Phone == identifier));
            if (userInfo == null)
                return GetResult.Error("账号或密码错误");

            if (userInfo.PassWord != password)
                return GetResult.Error("账号或密码错误");

            var allRoleNameList = userInfo.UserRoles.Select(x => x.Role.Name.ToLower()).ToList();

            if (GlobalService.SystemConfigGlobal.EnableSafeMode)
            {
                //验证端口
                switch (request.ClientType)
                {
                    case ClientTypeConst.Customer:
                        //含有客户角色就能访问客户端
                        if (!allRoleNameList.Contains(GlobalService.DefaultData.CustomerRoleName.ToLower()))
                            return GetResult.Error("无权访问");
                        break;
                    case ClientTypeConst.Admin:
                        //如果只有客户角色，则无法登陆客户端
                        if (allRoleNameList.Count <= 1 && allRoleNameList.Any(a => a == GlobalService.DefaultData.CustomerRoleName))
                            return GetResult.Error("无权访问");
                        break;
                    default:
                        return GetResult.Error("无权访问");
                }
            }

            #endregion

            #region 生成Token
            string strRole = string.Join(",", allRoleNameList);
            var tokenData = new GlobalUserInfoModel
            {
                UserId = userInfo.Id,
                UserName = userInfo.UserName,
                Account = userInfo.Account,
                ClientType = request.ClientType
            };

            var loginInfo = _userLoginsRepository.GetFirst(p => p.Account == userInfo.Account);
            var token = JwtHelper.CreateJWTToken(tokenData);

            if (string.IsNullOrEmpty(token))
            {
                return GetResult.Error("操作失败");
            }

            if (!AddOrUpdateLoginInfo(loginInfo, token, userInfo.Account))
            {
                return GetResult.Error("操作失败");
            };

            tokenData.Token = token;
            return GetResult.Success("登录成功", token);

            #endregion
        }

        public ResultInfoModel Logout(string account)
        {
            if (string.IsNullOrEmpty(account))
                return GetResult.Error("退出失败，找不到token");

            var loginInfo = _userLoginsRepository.GetFirst(p => p.Account == account);
            if (!AddOrUpdateLoginInfo(loginInfo, "", account))
            {
                return GetResult.Error("退出失败");
            };

            return GetResult.Success("退出成功");
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 新增或更新登录信息
        /// </summary>
        /// <param name="loginInfo"></param>
        /// <param name="token"></param>
        /// <param name="accoutId"></param>
        /// <returns></returns>
        private bool AddOrUpdateLoginInfo(UserLogin loginInfo, string token, string account)
        {
            try
            {
                var updateInfo = new UserLogin
                {
                    ExpireTime = DateTime.Now.AddMinutes(45),
                    CreateTime = DateTime.Now,
                    Token = token,
                    Account = account
                };

                if (loginInfo == null)
                {
                    return _userLoginsRepository.Insert(updateInfo);
                }
                else
                {
                    updateInfo.Id = loginInfo.Id;
                    return _userLoginsRepository.AsUpdateable(updateInfo).UpdateColumns(p => new { p.Token, p.ExpireTime }).Where(p => p.Id == updateInfo.Id).ExecuteCommand() > 0;
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(LogEnum.System, "AddOrUpdateLoginInfo", ex);
                return false;
            }
        }

        /// <summary>
        /// 判断Token是否有效
        /// </summary>
        /// <param name="loginInfo"></param>
        /// <returns></returns>
        private bool IsValidToken(UserLogin loginInfo)
        {
            //判断Token是否过期
            if (loginInfo == null || string.IsNullOrEmpty(loginInfo.Token) || loginInfo.ExpireTime < DateTime.Now || JwtHelper.IsExpired(loginInfo.Token))
            {
                return false;
            }

            return true;
        }

        private bool CheckAccountValid(string account)
        {
            return _userRepository.GetFirst(p => p.UserName == account && p.IsEnable == 1) != null;
        }

        #endregion
    }
}
